/* 
Copyright (c) 2004,2005, 2006, 2007, 2008 University of Illinois 

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* Functions for the List of DHTML/Widgets 
 * romanows, 2/18/06
 */

/* FIXME: Refactor to generalize to multiple treeboxes in one dialog.  
 * Have accessor functions that differentiate between, say, UpdateTreeBox()
 * and UpdateTreeBoxMain(); each of these calls a function UpdateTreeBoxCommon(treebox, xyz)
 */
AccessibilityExtension.ns(function() { with (AccessibilityExtension.LIB) {

	var AE = AccessibilityExtension.ns;  
	AE.dialogName = "accessext-form-list-dhtml";	

	var watchlist = new Array();
	
	/*
	 * Watch Workings:
	 * User adds a widget to watchlist.  When AE.primaryarray is updated, the widgets in the watchlist
	 * are added from it to AE.watcharray, while a function "overrides" the getTreeItem() function in the Widget object to
	 * correspond to what the watch treebox is looking for. 
	 */ 
	
	var tbObj;
	var tbObj_main;
	var tbObj_state;
	
	//10/29/07 SMF This class is use to keep triples together. The triple are read from aaa-qname.dtd.
	function dtdTripleObject(aaaname, aaavalue, aaaoptional) {
		this.aaaname = aaaname;
		this.aaavalue = cleanSpaces(aaavalue.replace(/\(|\)/g, '')).toLowerCase();
		this.aaaoptional = aaaoptional;
	}
	
	dtdTripleObject.prototype = {
		aaaname : "",
		aaavalue : "",
		aaaoptional : ""
	}
	
AccessibilityExtension.LIB.extend(AccessibilityExtension.LIB,
{
	//10/29/07 SMF Read the triples from aaa-qname.dtd.
	/**
	 * Read the triples from aria-qname.dtd into intoArray.
	 * @param {elementname} aaaValidStates, aaaValidProperties - these are defined in listofdhtml.xul
	 * 						and they are filled/loaded from aria-qname.dtd 
	 * 						aria-qname.dtd was modified, at the end of the file, to expose the states/properties 
	 * 							<!ENTITY AccessExtAAAStates "%aaa.states.qname;">
	 * 							<!ENTITY AccessExtAAAProperties "%aaa.props.qname;">
	 * @param {intoArray}  validStateValuesArray or validPropertyValuesArray (defined in this file)
	 * @return nothing.
	 * @author Sandy Foltz
	*/
	readAAATriples: function(elementname, intoArray) {
		try {
			var statename, validValues, lastValue;
		   	var aaaValidStates = document.getElementById(elementname).value;  
			
			var strLen = aaaValidStates.length;
			var currindex = 0;
			while (currindex < strLen && aaaValidStates.substring(currindex, currindex+1) == ' ') { currindex++; }
			while (currindex < strLen) {
				var nextSP = aaaValidStates.indexOf(' ', currindex);
				statename = aaaValidStates.substring(currindex, nextSP);
				for (currindex += statename.length+1; strLen && aaaValidStates.substring(currindex, currindex+1) == ' '; currindex++);
				if (aaaValidStates.substring(currindex, currindex+1) == '(') {
					nextSP = aaaValidStates.indexOf( ')', currindex) + 1;
					validValues = aaaValidStates.substring(currindex, nextSP);
				} else {
					nextSP = aaaValidStates.indexOf(' ', currindex);
					validValues = aaaValidStates.substring(currindex, nextSP);		
				}
				for (currindex += validValues.length+1; strLen && aaaValidStates.substring(currindex, currindex+1) == ' '; currindex++);
				nextSP = aaaValidStates.indexOf(' ', currindex);
				lastValue = aaaValidStates.substring(currindex, nextSP);		
				for (currindex += lastValue.length+1; currindex < strLen && aaaValidStates.substring(currindex, currindex+1) == ' '; currindex++);
				intoArray[intoArray.length] = new dtdTripleObject(statename, validValues, lastValue);
	
				//skip <statename>-list values
				nextSP = aaaValidStates.indexOf(' ', currindex);
				statename = aaaValidStates.substring(currindex, nextSP);		
				for (currindex += statename.length; currindex < strLen && aaaValidStates.substring(currindex, currindex+1) == ' '; currindex++);			
			}
		} catch (ex) {
			accessext_consoleDump('readAAATriples exception: ', ex);
		}
	},
	
	// Hack.  Need to present two different types of tree nodes for the two different treeboxes.
	// This wrapper overrides the normal getTreeNode() to provide the correct functionality for the 
	// bottom treebox.
	statesWidgetWrapper: function(widgetOrig) {
	   // Clone object
	   widget = widgetOrig.clone();
	   widget.getTreeNode = function(windoc) {
	      // Copied from "accesxt_generateTreeboxResults" in treebox_class.js
	      var item, child;
	      var row = windoc.createElement("treerow");
	
	      // Add values
	      child = windoc.createElement("treecell");
	      child.setAttribute("label",this.order);
	      row.appendChild(child);
	      child = windoc.createElement("treecell");
		  if (this.id != "") {//SMF 8/13/07 this.id may be empty, if so show what it shows in the top box
	      	child.setAttribute("label",this.id); 
	      }else {
	     	child.setAttribute("label",this.title); 	  	
		  }
		  row.appendChild(child);
	
	      // Add state values
	      if(this.states.length) {
	         for (var col in this.states[0].allStates) {
	            var colName = this.states[0].allStates[col];
	            child = windoc.createElement("treecell");
	            var value = (this.getState(colName) == null) ? "" : this.getState(colName).value;
	            child.setAttribute("label",value);
	            row.appendChild(child);
	         }
	      }
	      item = windoc.createElement("treeitem");
	      item.appendChild(row);
	      return item;
	   }
	   return(widget);
	},
	
	/**
	 * for loading the widget list headers.
	 * @return array of column headers for the widget list
	 * @author Sandy Foltz
	*/
	loadWidgetColumnHeaders: function() {
	   var cols = new Array();
	   cols['list-header-main-order'] = 'order';
	   cols['list-header-main-widget'] = 'id'; //'widget'
	   cols['list-header-main-role'] = 'role';
	   cols['list-header-main-tabIndex'] = 'tabIndex';
	   cols['list-header-main-hasChanged'] = 'hasChanged';
	   cols['list-header-main-watch'] = 'watch';
	   return cols;	
	},
	
	/**
	 * for loading the widget list headers.
	 * @return array of column headers for the widget list
	 * @author Sandy Foltz
	*/
	loadStateColumnHeaders: function() {
	   var cols = new Array();
	   cols['list-header-state-order'] = 'order';
	   cols['list-header-state-name'] = 'state';
	   cols['list-header-state-value'] = 'value';
	   return cols;	
	},
	
	/**
	 * for loading the watch list headers.
	 * @return array of column headers for the watch list
	 * @author Sandy Foltz
	*/

	loadWatchColumnHeaders: function() {
	   var cols = new Array();
	   cols['list-header-checked'] = 'checked';
	   cols['list-header-iconed'] = 'iconed';
	   cols['list-header-disabled'] = 'disabled';
	   cols['list-header-readonly'] = 'readonly';
	   cols['list-header-multiselectable'] = 'multiselectable';
	   cols['list-header-domactive'] = 'domactive';
	   cols['list-header-zoom'] = 'zoom';
	   cols['list-header-expanded'] = 'expanded';
	   cols['list-header-selected'] = 'selected';
	   cols['list-header-pressed'] = 'pressed';
	   cols['list-header-important'] = 'important';
	   cols['list-header-required'] = 'required';
	   cols['list-header-haseffect'] = 'haseffect';
	   cols['list-header-valuenow'] = 'valuenow';
	   cols['list-header-valuemax'] = 'valuemax';
	   cols['list-header-valuemin'] = 'valuemin';
	   cols['list-header-step'] = 'step';
	   cols['list-header-invalid'] = 'invalid';
	   cols['list-header-describedby'] = 'describedby';
	   cols['list-header-labeledby'] = 'labeledby';
	   cols['list-header-hasparent'] = 'hasparent';
	   cols['list-header-haschild'] = 'haschild';
	   cols['list-header-haspopup'] = 'haspopup';
	   cols['list-header-alternatestyle'] = 'alternatestyle';
	   cols['list-header-tabindex'] = 'tabindex';
	   cols['list-header-flowto'] = 'flowto';
	   cols['list-header-flowfrom'] = 'flowfrom';
	   cols['list-header-controls'] = 'controls';
	   cols['list-header-controlledby'] = 'controlledby';
	   cols['list-header-subpageof'] = 'subpageof';
	   return cols;	
	},
	
	initTreeboxDHTML: function() {
	   var widgetColumnHeaders = loadWidgetColumnHeaders();
	   tbObj_main = newTreeboxObject('treebox-main',widgetColumnHeaders,'list-header-main-order');
	 
	   var stateColumnHeaders = loadStateColumnHeaders();
	   tbObj_state = newTreeboxObject('treebox',stateColumnHeaders,'list-header-state-order');
	  
	   var watchCols = loadWatchColumnHeaders();
	   tbObj = newTreeboxObject('treebox-watch',watchCols,'list-header-order');
	},
	
	updatePointers_common: function() {
		//AE.thewindow & AE.mydoc are retreived differently for dialog vs sidebar
		try {  // from the accessibility Issues Dialog
			if (window.opener.name == 'accessext-issues') {
				var accessibilityIssuesDialog = window.opener.parent;
				AE.thewindow = accessibilityIssuesDialog.opener.parent._content;			
			} else {
				AE.thewindow = window.opener.parent._content;
			}
		} catch (e){
			try { // dialog way 
				AE.thewindow = window.opener.parent._content;
			} catch(e) { 
				AE.thewindow = window.parent._content;
			}
		}
		/*
		 * SF 8/10/07 highlighting and catching button pushes are not being captured when in sidebar
		 * error may be here or in each individual area.
		 */
		AE.mydoc = AE.thewindow.document;		
		AE.treebox_watch = document.getElementById("treebox-watch");
		AE.treebox = document.getElementById("treebox");
		AE.treebox_main = document.getElementById("treebox-main");
		AE.primaryarray = new Array();
		AE.dataarray = new Array();
		AE.watcharray = new Array();

/*		function browserPageLoaded() {AccessibilityExtension.LIB.InitAccessibilityExt(); }
		function tryAgain() {
			var bodynode = AE.mydoc.getElementsByTagName("body");
	        if (bodynode) {
	        	bodynode[0].addEventListener("load", browserPageLoaded, false);
	        	alert('addEventListener done');
	        }
	        else {
	             setTimeout (tryAgain, 500);
	        }
		}
	    try {
	 		var bodynode = AE.mydoc.getElementsByTagName("body");
			if (!(bodynode))
	            throw "tantrum";
			else {
				bodynode[0].addEventListener("load", browserPageLoaded, false);
	        	alert('addEventListener done');
			}       
	    }
	    catch (ex) {
	        setTimeout (tryAgain, 500);
	        return;
	    }// need to wait until the browser page loads	
		*/

	},
	
	updatePointers: function() {
	   updatePointers_common();   
	   initTreeboxDHTML();
	},
	
	InitAccessibilityExt: function() { 
		var dialogEle = document.getElementById("widget-accessiblename-hbox");
		if (dialogEle == null) return; //not in listofdhtml.xul so skip this function
		InitAccessibilityExt_common();
	    recursiveAddEventListener(AE.mydoc, "DOMAttrModified", accessext_eventRefreshOnWidgetAttr, true);
	},
	
	accessext_eventRefreshOnWidgetAttr: function(event) {
	   // relatedNode is not set when attribute is first removed.  The DOM spec indicates that the attribute should be 
	   // ... removed from the tree before the DOMAttrModified event is fired, but Mozilla fires it before it is removed.  
	   // ... The information we have available is the target element node, the attribute name, and the attribute's old and new values.
	   // ... However, the important namespace information is missing from the attribute name.  Thus, if ever two "checked" attributes 
	   // ... appear and the non-aaa one is removed, then we'll screw up (unlikely).
	   
	   // true if relatedNode is null or a state attribute
	
	   if( event.relatedNode==null ? true : isStateAttribute(event.relatedNode) ) {
	      // Find which widget node (in our AE.primaryarray) this attribute corresponds to 
	      for(var i=0; i<AE.primaryarray.length; i++) {
	         if(AE.primaryarray[i].id == event.target.id) {
	            // If it is ADDITION, add this state to the array
	            if(event.attrChange == event.ADDITION) {
	               AE.primaryarray[i].states[AE.primaryarray[i].states.length] = newaaaStateObject(event.relatedNode);
	               AE.primaryarray[i].states[AE.primaryarray[i].states.length-1].hasChanged = true;
	            } else {
	               // Find the appropriate existing state to modify
	               for(var j=0; j<AE.primaryarray[i].states.length; j++) {
				   	  var eveAttName = event.attrName;
				   	  if (event.attrName.indexOf('aria-') == 0) {
					  	eveAttName = event.attrName.substring(5);
					  }
					  if(AE.primaryarray[i].states[j].state == eveAttName) {
	                     // If this is REMOVAL operation, remove this state from the array
	                     if(event.attrChange == event.REMOVAL) {
	                        AE.primaryarray[i].states.splice(j,1); // remove the jth element
	                     }
	                     // If it is MODIFICATION, change the value
	                     if(event.attrChange == event.MODIFICATION) {
	                        AE.primaryarray[i].states[j].lastValue = event.prevValue;
	                        AE.primaryarray[i].states[j].value = event.newValue;
	                        AE.primaryarray[i].states[j].hasChanged = true;
	                     }
	                  }
	               }
	            }
	            AE.primaryarray[i].hasChanged = true;
	            RefreshListView();
	            break;
	         }
	      }
	   }
	},
	
	// Copied from RefreshList, should refresh the view without reloading AE.primaryarray from the DOM tree
	RefreshListView: function() {
	   var tempCurrentIndexMain=AE.treebox_main.currentIndex;
	   var tempCurrentIndexWatch=AE.treebox_watch.currentIndex;
	
	   tbObj_main.setDataArray(AE.primaryarray);
	   UpdateTreeViewMain();
	
	   AE.treebox_main.view.selection.select(tempCurrentIndexMain);
	
	   // Generate watch array
	   // Loop through AE.primaryarray, if the id matches one in watchlist, add it to AE.watcharray.
	   AE.watcharray = new Array();
	   for(var i=0; i<AE.primaryarray.length; i++) {
	      for(var j=0; j<watchlist.length; j++) {
	 	  	if (AE.primaryarray[i].id != "") {//SMF 8/13/07 id may be empty, if so show what it shows in the top box
		        if(AE.primaryarray[i].id == watchlist[j]) {
		            AddTowatcharray(AE.primaryarray[i]);
		
		            // FIXME: Here, add new columns to the tree view if the states do not appear in the standard,
		            // ... and style their background so it is more obvious.
		            // ... a varient on createElement, appendElement to treebox-treecols
		            // ... with an id of list-header-new-XXX, where XXX is the name of the new state
		            // ... and you should search the id's to make sure it is not already present.
		            // unhide columns that the AE.primaryarray widget includes states for
		            for(var q=0; q<AE.primaryarray[i].states.length; q++) {
		               if(AE.primaryarray[i].states[q].isStandardState()) {
		                  document.getElementById('list-header-'+AE.primaryarray[i].states[q].state).hidden=false;
		               }
		            }
		         }
			}else {
		        if(AE.primaryarray[i].title == watchlist[j]) {
		            AddTowatcharray(AE.primaryarray[i]);
		
		            // FIXME: same comment as above
		            for(var q=0; q<AE.primaryarray[i].states.length; q++) {
		               if(AE.primaryarray[i].states[q].isStandardState()) {
		                  document.getElementById('list-header-'+AE.primaryarray[i].states[q].state).hidden=false;
		               }
		            }
		         }
				
			}
	      }
	   }
	
	   tbObj.setDataArray(AE.watcharray);
	   UpdateTreeViewWatch();
	   AE.treebox_watch.view.selection.select(tempCurrentIndexWatch);
	},
	
	// Scans the DOM to create a list of relevant objects and updates our tree view
	RefreshList: function() {
	   updatePointers();
	   
	   accessext_setNoteText(-1);
	   
	   var documents = accessext_getDocuments(AE.thewindow,new Array());
	       
	   for (var i=0; i < documents.length; i++) {
	      ParseDocument(documents[i]);
	   }
	
	   tbObj_main.setDataArray(AE.primaryarray);
	   UpdateTreeViewMain();
	
	   // Generate watch array
	   // Loop through AE.primaryarray, if the id matches one in watchlist, add it to AE.watcharray.
	   for(var i=0; i<AE.primaryarray.length; i++) {
	      for(var j=0; j<watchlist.length; j++) {
		  	if (AE.primaryarray[i].id != "") {//SMF 8/13/07 id may be empty, if so show what it shows in the top box
	         	if(AE.primaryarray[i].id == watchlist[j]) {
	            	AddTowatcharray(AE.primaryarray[i]);
	         	}
			}else {
	         	if(AE.primaryarray[i].title == watchlist[j]) {
	            	AddTowatcharray(AE.primaryarray[i]);
	         	}			
			}	
	      }
	   }
	   // Display Accessible Name & description information in the textbox  
	   document.getElementById("widget-accessiblename-textbox").value = ''; 
	   document.getElementById("widget-description-textbox").value = ''; 
	     
	   tbObj.setDataArray(AE.dataarray);
	   UpdateTreeViewState();
	  
	   tbObj.setDataArray(AE.watcharray);
	   UpdateTreeViewWatch();
	},
	
	UpdateTreeViewMain: function() {
	   var widgetColumnHeaders = loadWidgetColumnHeaders();
	   UpdateTreeView_common(AE.treebox_main,'order',AE.sortColumn_main,widgetColumnHeaders,AE.primaryarray);
		accessext_tree_autoselect_main();
	},
	
	UpdateTreeViewState: function() {
		var stateColumnHeaders = loadStateColumnHeaders();
		UpdateTreeView_common(AE.treebox,'order',AE.sortColumn_state,stateColumnHeaders,AE.dataarray);
		accessext_tree_autoselect_state();
	},
	
	UpdateTreeViewWatch: function() {
	   var watchCols = loadWatchColumnHeaders(); 
	    UpdateTreeView_common(AE.treebox_watch,'order',AE.sortColumn,watchCols,AE.watcharray);
	},
	
	// Removes any existing handlers
	accessext_dhtmlWatchClose: function() {
	   AE.mydoc.removeEventListener("DOMAttrModified",accessext_eventRefreshOnWidgetAttr,true);
	   CleanUp();
	   window.close();
	},
	
	accessext_dhtmlgetstates: function(findex) {
	   var stateStr = "";
	   var widget = AE.primaryarray[findex];
	
	   // Form the string of states
	   var stateStr = "";
	   if( widget.states.length > 0 ) {
	      for(var i=0; i<widget.states.length-1; i++) {
	         stateStr = stateStr + widget.states[i].state + "=" + widget.states[i].value + ", ";
	      }
	      // No comma on this last one
	      stateStr = stateStr + widget.states[widget.states.length-1].state + "=" + widget.states[widget.states.length-1].value;
	   } else {
	      stateStr = accessext_getBundleSingleString('none');
	   }
	   return stateStr;
	},
	
	// When a row in the treebox_main is selected, this is called
	accessext_handle_treebox_main: function() {
	   // If we've selected something sensical
	   if(AE.treebox_main.currentIndex < 0 || AE.treebox_main.currentIndex >= AE.primaryarray.length)
	      return;
	
	   // If what we've selected "exists" (is not null) in the document
	   var findex = AE.treebox_main.currentIndex;
	   var node = AE.primaryarray[findex].node;
	   if(node == null || AE.mydoc == null)
	     return;
	
	   accessext_scrollAndHighlightNode(node);
	   
	   accessext_setNoteText(findex);
	
	   // Display Accessible Name & description information in the textbox  
	   document.getElementById("widget-accessiblename-textbox").value = AE.primaryarray[findex].getStateValueInPage('labelledby'); 
	   document.getElementById("widget-description-textbox").value = AE.primaryarray[findex].getStateValueInPage('describedby'); 
		
	   try {
		   AE.dataarray = AE.primaryarray[findex].states;
		   tbObj.setDataArray(AE.dataarray);
		   UpdateTreeViewState();
		}	
		catch(e) {
			//accessext_consoleDump('RefreshListView: ' + e);
		}
	},
	
	accessext_dhtmlAddWatchToArray: function(selectionIndex) {
	   var node = AE.primaryarray[selectionIndex].node;
	   if(node == null || AE.mydoc == null)
	      return;
	
	   // Have we already added watch?
	   var found = false;
	   for(var i=0; i<watchlist.length; i++) {
		  if (AE.primaryarray[selectionIndex].id != "") {//SMF 8/13/07 id may be empty, if so show what it shows in the top box
		      if(watchlist[i] == AE.primaryarray[selectionIndex].id) {
		         found = true;
		      }
		   } else{
		      if(watchlist[i] == AE.primaryarray[selectionIndex].title) {
		         found = true;
		      }	   	
		   }
	   }
	      
	   if(found==false) {
	 	  if (AE.primaryarray[selectionIndex].id != "") {//SMF 8/13/07 id may be empty, if so show what it shows in the top box
	      	watchlist[watchlist.length] = AE.primaryarray[selectionIndex].id;
	      }else {
	     	watchlist[watchlist.length] = AE.primaryarray[selectionIndex].title;	  	
		  }
	   }
	   AE.primaryarray[selectionIndex].watch = true;
	},
	
	// Called by the .xul button; adds the appropriate widget to the array for the watch tree
	accessext_dhtmlAddWatch: function() {
	   var findex = AE.treebox_main.currentIndex;
	   accessext_dhtmlAddWatchToArray(findex);   
	   RefreshListView();
	},
	
	// Called by the .xul button; adds all the appropriate widgets to the array for the watch tree
	accessext_dhtmlAddWatchAll: function() {
	   for(var i=0; i<AE.primaryarray.length; i++) {
	      accessext_dhtmlAddWatchToArray(i);  
	   }
	   RefreshListView();
	},
	
	accessext_dhtmlRemoveWatch: function() {
	   var findex = AE.treebox_watch.currentIndex;
	   
		for(var i=0; i<AE.primaryarray.length; i++) {
			if (AE.primaryarray[i].id != "") {//SMF 8/13/07 id may be empty, if so show what it shows in the top box
			     if(AE.primaryarray[i].id == watchlist[findex]){
			         AE.primaryarray[i].watch = false;
				}
			}
			else if(AE.primaryarray[i].title == watchlist[findex]) {
				AE.primaryarray[i].watch = false;
			}
		}
	   
	   // remove the entry at the current index from the watchlist
	   watchlist.splice(findex,1);
	   RefreshListView();
	},
	
	// Called by the .xul button; adds all the appropriate widgets to the array for the watch tree
	accessext_dhtmlRemoveWatchAll: function() {
		for(var i=0; i<AE.primaryarray.length; i++) {
			AE.primaryarray[i].watch = false;
		}
	   watchlist = new Array();
	   RefreshListView();
	},
	
	AddTowatcharray: function(widget) {
	   var index = AE.watcharray.length;
	   AE.watcharray[index] = statesWidgetWrapper(widget);
	},
	
	accessext_handle_listbox: function() {
	   UpdateTreeViewWatch();
	},
	
	ParseDocument: function(node) { 
	   //10/29/07 read the state and properties from aaa
		readAAATriples("aaaValidStates", AE.validStateValuesArray);
		readAAATriples("aaaValidProperties", AE.validPropertyValuesArray);
	
		ParseDocumentForWidget(node, AE.primaryarray);
		return;
	},
	
	ARIAWidgetRefresh: function() {
	    AE.mydoc.removeEventListener("DOMAttrModified",accessext_eventRefreshOnWidgetAttr,true);
		tempCurrentIndex=document.getElementById('treebox-main').currentIndex;
	    recursiveAddEventListener(AE.mydoc, "DOMAttrModified", accessext_eventRefreshOnWidgetAttr, true);
		RefreshList();
		if (tempCurrentIndex > document.getElementById('treebox-main').length) {
			tempCurrentIndex = 0;
		}
	//	alert('There may be a timing issue this alert helped at one point.')
		document.getElementById('treebox-main').view.selection.select(tempCurrentIndex);
		document.getElementById('treebox-main').focus();
	},
	
	//10/15/07 SMF This never get executed since InitAccessibilityExt_common() is used instead of InitAccessibilityExt()
	post_InitAccessibilityExt: function() {
		accessext_loadDialogPrefs();
		accessext_setNoteCaption();
		accessext_setNoteText(0);
	},
	
	toggleState: function() {
		try {
			//still getting called even when button is disabled, Why?
			var toggleBtn = document.getElementById('toggle-state-value');
			if (toggleBtn.getAttribute("disabled") == true) return;
			
	 		var findex = AE.treebox_main.currentIndex;
			var stateTree = document.getElementById("treebox");
			var index = stateTree.currentIndex;
			var currVal = AE.primaryarray[findex].states[index].value.toLowerCase();
			var statevalues;
			var newVal = -1;
	
			for (i=0; i<AE.validStateValuesArray.length && newVal==-1; i++) {
				if (AE.validStateValuesArray[i].aaaname==AE.primaryarray[findex].states[index].state) {
					statevalues = AE.validStateValuesArray[i].aaavalue.split(' | ');
					for (var i = 0; i < statevalues.length; i++) {
						if (statevalues[i] == currVal) newVal = i + 1;
					}
					if (newVal == statevalues.length) newVal = 0;
		      	}
		   }
		   if (newVal == -1) newVal = 0;
		   
			AE.primaryarray[findex].node.setAttribute('aria-' + AE.primaryarray[findex].states[index].state,statevalues[newVal]);	
			AE.primaryarray[findex].states[index].value = statevalues[newVal];
			UpdateTreeViewState(); 	
		} catch (ex) {
			accessext_consoleDump('toggleState exception: ', ex);
		}
	},
	
	setStateValue: function() {
		try {
			function isInteger(sText)	{
				var ValidChars = "0123456789";
				if (sText.length == 0) return false;
				for (i = 0; i < sText.length; i++) { 
					if (ValidChars.indexOf(sText.charAt(i)) == -1) return false;
				}
				return true;
			}		
	  		var findex = AE.treebox_main.currentIndex;
			var stateTree = document.getElementById("treebox");
			var index = stateTree.currentIndex;
			var stateValueEle = document.getElementById("state-value-textbox");
			if (stateValueEle.hasAttribute("value")) {
				var value = stateValueEle.value;
				var min = 0;
				var max = 0;
				if (isInteger(value)) {
					for (var i = 0; i < AE.primaryarray[findex].states.length; i++) {
						if (AE.primaryarray[findex].states[i].state.toLowerCase() == 'valuemin') min = AE.primaryarray[findex].states[i].value;
						if (AE.primaryarray[findex].states[i].state.toLowerCase() == 'valuemax') max = AE.primaryarray[findex].states[i].value;
					}
					if (parseInt(value) < parseInt(min)) {alert(accessext_getBundleSingleString('valuenow.toosmall').replace('%1', min)); return;}
					if (parseInt(value) > parseInt(max)) {alert(accessext_getBundleSingleString('valuenow.toolarge').replace('%1', max)); return;}
					AE.primaryarray[findex].node.setAttribute('aria-' + AE.primaryarray[findex].states[index].state,value);	
					AE.primaryarray[findex].states[index].value = value;
					UpdateTreeViewState(); 	
				} else {
					alert(accessext_getBundleSingleString('valuenow.invalid'))
				}
			}
		} catch (ex) {
			accessext_consoleDump('setStateValue exception: ', ex);
		}	
	},
	
	accessext_state_select: function() {
		try {
	  		var findex = AE.treebox_main.currentIndex;
			var stateTree = document.getElementById("treebox");
			var index = stateTree.currentIndex;
			if (index < 0 || index > AE.dataarray.length) {
				return false;
			}
			var togglebutton = document.getElementById("toggle-state-value");
			if (null != togglebutton) {
				if (AE.primaryarray[findex].states[index]) {
					var toggable = ['checked','expanded', 'grab','pressed','selected','sort'];
					togglebutton.disabled = (toggable.indexOf(AE.primaryarray[findex].states[index].state.toLowerCase()) == -1);
				}
			}
			var valuelabel = document.getElementById("state-value-label");
			var applybutton = document.getElementById("buttonActivate"); 
			var valueTextbox = document.getElementById("state-value-textbox");
			if (null != applybutton && null != valueTextbox) {
				if (AE.primaryarray[findex].states[index] && AE.primaryarray[findex].states[index].state.toLowerCase() == 'valuenow') {
					valuelabel.disabled = applybutton.disabled = valueTextbox.disabled = false; 
				}
				else {
					valuelabel.disabled = applybutton.disabled = valueTextbox.disabled = true;
				}
			}
	
			return true;
		} catch (ex) {
			accessext_consoleDump('accessext_state_select exception: ', ex);
		}
	},
	
	accessext_tree_autoselect_state: function() {
		try {
	  		var findex = AE.treebox_main.currentIndex;
			var stateTree = document.getElementById("treebox");
			if (AE.primaryarray[findex].states.length > 0 && stateTree.currentIndex < 0) {
				stateTree.currentIndex=0;
				stateTree.view.selection.select(0);
			}
		} catch (ex) {
// when the objects have not fully loaded you can get this error.
//			accessext_consoleDump('accessext_tree_autoselect_state exception: ', ex);
		}
	},
	
	accessext_toggleSortColumn_state: function(column) {
		if (column == AE.sortColumn_state)
			AE.sortDirectionAscending_state = !AE.sortDirectionAscending_state;
		else {
			AE.sortDirectionAscending_state = true;
			AE.sortColumn_state = column;
		}
		sortDirection=AE.sortDirectionAscending_state; //sortDirection is used by updateTreeView()
		UpdateTreeViewMain();
	}
});
//if (AccessibilityExtension.LIB.updatePointers_common) AccessibilityExtension.LIB.updatePointers_common();	
if (AccessibilityExtension.LIB.InitAccessibilityExt) AccessibilityExtension.LIB.InitAccessibilityExt();		
}});	